package com.feihong.yw189.bluetooth.utils.djlm.newDJMLReader;

import com.feihong.yw189.bluetooth.utils.util.HexUtil;

import java.io.IOException;
import java.util.Arrays;

/**
 * 2016/10/23
 */
public class DJML_SIMCard {
    //SIM卡命令处理接口
    public static byte[] BLECmd(DJLM_BLEService service, int nCmdType, byte[] send) throws IOException {
        byte[] ret = null;
        service.GetLastNotification(0);
        byte[] buff = new byte[send.length + 2];
        buff[0] = (byte) nCmdType;
        buff[1] = (byte) send.length;
        System.arraycopy(send, 0, buff, 2, send.length);
        System.out.println("send:" + HexUtil.bytesToHexString(buff));
        byte[] notification = null;
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (!service.writeRXCharacteristic2(buff)) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (!service.writeRXCharacteristic2(buff))
                throw new IOException("writeRXCharacteristic2 error!");
        } else {
            //
        }
        notification = service.GetLastNotification(1200);
        if (notification != null) {
            System.out.println("rev:" + HexUtil.bytesToHexString(notification));
            if (notification[0] == 0) {
                ret = new byte[notification[1]];
                System.arraycopy(notification, 2, ret, 0, notification[1]);
            }
        } else {
            //
        }
        return ret;
    }

    //COS命令执行
    static byte[] Apdu(DJLM_BLEService service, byte[] send) throws IOException {
        if (send.length > 16) {
            return MultApdu(service, send);
        } else
            return BLECmd(service, 2, send);
    }

    //COS命令执行
    static byte[] MultApdu(DJLM_BLEService service, byte[] Send) throws IOException {
        int nSendLen = 0;
        while (nSendLen < Send.length) {
            int nThisLen = Send.length - nSendLen;
            if (nThisLen > 15)
                nThisLen = 15;
            byte[] buff = new byte[nThisLen + 1];
            buff[0] = (byte) nSendLen;
            System.arraycopy(Send, nSendLen, buff, 1, nThisLen);
            BLECmd(service, 3, buff);
            nSendLen += nThisLen;
        }
        return BLECmd(service, 4, new byte[]{(byte) Send.length});
    }

    //获取读卡设备序列号及版本信息
    static byte[] ReaderInfo(DJLM_BLEService service) throws IOException {
        return BLECmd(service, 11, "1".getBytes());
    }

    //蜂鸣器发声
    public static void Beep(DJLM_BLEService service) throws IOException {
        BLECmd(service, 10, "1".getBytes());
    }

    static String VersionInfo(DJLM_BLEService service) throws IOException {
        byte[] ret = BLECmd(service, 11, "1".getBytes());
        if (ret != null) {
            String strRet = ret[0] + "," + ret[1] + "." + ret[2] + ret[3] + ret[4];
            StringBuilder stringBuilder = new StringBuilder("");
            for (int i = 0; i < 6; i++) {
                int v = ret[5 + (5 - i)] & 0xFF;
                String hv = Integer.toHexString(v).toUpperCase();
                if (hv.length() < 2) {
                    stringBuilder.append(0);
                }
                stringBuilder.append(hv);
                if (i != 5)
                    stringBuilder.append(':');
            }
            strRet += "," + stringBuilder.toString();
            return strRet;
        }
        return null;
    }

    /**
     * 获取版本号 ，获取成功返回大于0 的值 ，失败返回0
     *
     * @param service
     * @return
     * @throws IOException
     */
    public static float GetVerFloat(DJLM_BLEService service) {
        byte[] ret = new byte[0];
        try {
            ret = BLECmd(service, 11, "1".getBytes());
            if (ret != null) {
                String strVer = ret[1] + "." + ret[2] + ret[3] + ret[4];
                try {
                    return Float.parseFloat(strVer);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return 0;
    }

    /***
     * 获取高速或者低速模式 ： 大于20 说明低速  否则低速  新增的方法 只能1.027 可用
     * @param service
     * @return 0--100只
     * @throws IOException
     */
    public static int GetInterval(DJLM_BLEService service) throws IOException {
        int nRetInterval = -1;
        int nInterval = 0;
        int nLatency = 0;
        byte[] ret = null;
        byte[] speedState = new byte[6];
        ret = BLECmd(service, 13, new byte[]{0});
        if (ret != null) {
            System.arraycopy(ret, 0, speedState, 0, 6);
            nInterval = ((ret[0] & 0x00FF) << 8) | (ret[1] & 0x00FF);
            nLatency = ((ret[2] & 0x00FF) << 8) | (ret[3] & 0x00FF);
            nRetInterval = nInterval * (nLatency + 1);
        }
        return nRetInterval;
    }

    /***
     * 获取电量 0---1000    新增的方法 只能1.027 可用
     * @param service
     * @return
     * @throws IOException
     */
    public static int GetBattery(DJLM_BLEService service) throws IOException {
        byte[] ret = null;
        int nRet = -1;
        ret = BLECmd(service, 14, new byte[]{0});
        if (ret != null) {
            nRet = ((ret[0] & 0x00FF) << 8) | (ret[1] & 0x00FF);
        }
        return nRet;
    }

    /***
     * 关机开机 成功 返回true 否则 返回false    新增的方法 只能1.027 可用
     * @param service
     * @return
     * @throws IOException
     */
    public static boolean PowerOff(DJLM_BLEService service) throws IOException {
        byte[] ret = null;
        ret = BLECmd(service, 15, new byte[]{0});
        if (ret != null) {
            return true;
        }
        return false;
    }

    static String GetVer(DJLM_BLEService service) throws IOException {
        byte[] ret = BLECmd(service, 11, "1".getBytes());
        if (ret != null) {
            String strVer = "V" + ret[1] + "." + ret[2] + ret[3] + ret[4];
            return strVer;
        }
        return null;
    }

    public static boolean BLEFast(DJLM_BLEService service, boolean bFast) throws IOException {
        byte[] ret = null;
        if (bFast) {
            ret = BLECmd(service, 12, new byte[]{1});
        } else {
            ret = BLECmd(service, 12, new byte[]{0});
        }
        if (ret != null)
            return true;
        return false;
    }

    //////////////////////////////////////////////////////////////////////////////
    //SIM卡选择文件的COS指令
    static int SelectFile(DJLM_BLEService service, int nFileID, byte[] SW) throws IOException {
        byte[] Query = new byte[]{(byte) 0xA0, (byte) 0xA4, 0x00, 0x00, 0x02, 0x2F, (byte) 0xE2};
        Query[5] = (byte) (nFileID / 0x100);
        Query[6] = (byte) (nFileID % 0x100);
        byte[] ret = Apdu(service, Query);
        if (ret == null) {
            return -1;
        } else {
            if (ret.length >= 2) {
                SW[0] = ret[ret.length - 2];
                SW[1] = ret[ret.length - 1];
            }
            return 0;
        }
    }

    //SIM卡二进制读的COS指令
    static byte[] ReadBinary(DJLM_BLEService service, int nPos, int nLen, byte[] SW) throws IOException {
        byte[] Query = new byte[]{(byte) 0xA0, (byte) 0xB0, 0x00, 0x00, 0x00};
        Query[2] = (byte) ((nPos / 0x100) & 0x7F);
        Query[3] = (byte) (nPos % 0x100);
        Query[4] = (byte) nLen;
        byte[] ret = Apdu(service, Query);
        if (ret != null) {
            if (ret.length >= 2) {
                SW[0] = ret[ret.length - 2];
                SW[1] = ret[ret.length - 1];
                if (ret.length > 2) {
                    byte[] data = new byte[ret.length - 2];
                    System.arraycopy(ret, 0, data, 0, ret.length - 2);
                    return data;
                }
            }
        }
        return null;
    }

    //SIM卡二进制写的COS指令
    static int WriteBinary(DJLM_BLEService service, int nPos, byte[] data, byte[] SW) throws IOException {
        byte[] Query = new byte[5 + data.length];
        Query[0] = (byte) 0xA0;
        Query[1] = (byte) 0xD6;
        Query[2] = (byte) ((nPos / 0x100) & 0x7F);
        Query[3] = (byte) (nPos % 0x100);
        Query[4] = (byte) data.length;
        System.arraycopy(data, 0, Query, 5, data.length);
        byte[] ret = Apdu(service, Query);
        if (ret == null) {
            return -1;
        } else {
            if (ret.length >= 2) {
                SW[0] = ret[ret.length - 2];
                SW[1] = ret[ret.length - 1];
            }
            return 0;
        }
    }

    //SIM卡读记录的COS指令
    static byte[] ReadRecord(DJLM_BLEService service, int nRecNo, int nMode, int nReadLen, byte[] SW) throws IOException {
        byte[] Query = new byte[]{(byte) 0xA0, (byte) 0xB2, 0x00, 0x00, 0x00};
        Query[2] = (byte) nRecNo;
        Query[3] = (byte) nMode;
        Query[4] = (byte) nReadLen;
        byte[] ret = Apdu(service, Query);
        if (ret != null) {
            if (ret.length >= 2) {
                SW[0] = ret[ret.length - 2];
                SW[1] = ret[ret.length - 1];
                if (ret.length > 2) {
                    byte[] data = new byte[ret.length - 2];
                    System.arraycopy(ret, 0, data, 0, ret.length - 2);
                    return data;
                }
            }
        }
        return null;
    }

    //SIM卡写记录的COS指令
    static int WriteRecord(DJLM_BLEService service, int nRecNo, int nMode, byte[] data, byte[] SW) throws IOException {
        byte[] Query = new byte[5 + data.length];
        Query[0] = (byte) 0xA0;
        Query[1] = (byte) 0xDC;
        Query[2] = (byte) nRecNo;
        Query[3] = (byte) nMode;
        Query[4] = (byte) data.length;
        System.arraycopy(data, 0, Query, 5, data.length);
        byte[] ret = Apdu(service, Query);
        if (ret == null) {
            return -1;
        } else {
            if (ret.length >= 2) {
                SW[0] = ret[ret.length - 2];
                SW[1] = ret[ret.length - 1];
            }
            return 0;
        }
    }

    //SIM卡写IMSICOS指令
    static int WriteIMSI(DJLM_BLEService service, byte[] data, byte[] SW) throws IOException {
        byte[] Query = new byte[5 + 18];
        Arrays.fill(Query, (byte) 0);
        Query[0] = (byte) 0xA0;
        Query[1] = (byte) 0xF4;
        Query[4] = (byte) 0x12;
        System.arraycopy(data, 0, Query, 5, 9);
        System.arraycopy(data, 0, Query, 5 + 9, 9);
        byte[] ret = Apdu(service, Query);
        if (ret == null) {
            return -1;
        } else {
            if (ret.length >= 2) {
                SW[0] = ret[ret.length - 2];
                SW[1] = ret[ret.length - 1];
            }
            return 0;
        }
    }

    static byte[] GetResponse(DJLM_BLEService service, int nLen, byte[] SW) throws IOException {
        byte[] Query = new byte[]{(byte) 0xA0, (byte) 0xC0, 0x00, 0x00, 0x00};
        Query[4] = (byte) nLen;
        byte[] ret = Apdu(service, Query);
        if (ret != null) {
            if (ret.length >= 2) {
                SW[0] = ret[ret.length - 2];
                SW[1] = ret[ret.length - 1];
                if (ret.length > 2) {
                    byte[] data = new byte[ret.length - 2];
                    System.arraycopy(ret, 0, data, 0, ret.length - 2);
                    return data;
                }
            }
        }
        return null;
    }

    static String GetRevBCDString(byte[] data) {
        byte[] temp = new byte[data.length * 2];
        for (int i = 0; i < data.length; i++) {
            if ((data[i] & 0xf) >= 0 && (data[i] & 0xf) <= 9)
                temp[i * 2] = (byte) ((data[i] & 0xf) + '0');
            else if ((data[i] & 0xf) >= 0xa && (data[i] & 0xf) <= 0xf)
                temp[i * 2] = (byte) ((data[i] & 0xf) + 'A' - 10);
            else
                temp[i * 2] = '?';

            if (((data[i] >> 4) & 0xf) >= 0 && ((data[i] >> 4) & 0xf) <= 9)
                temp[i * 2 + 1] = (byte) (((data[i] >> 4) & 0xf) + '0');
            else if (((data[i] >> 4) & 0xf) >= 0xa && ((data[i] >> 4) & 0xf) <= 0xf)
                temp[i * 2 + 1] = (byte) (((data[i] >> 4) & 0xf) + 'A' - 10);
            else
                temp[i * 2] = '?';
        }
        String strRet = new String(temp);
        return strRet;
    }

    static byte[] GetDataFromRevBCDString(String strData) {
        int i, n = 0;
        byte nData;
        byte nData2;
        if (strData.length() % 2 != 0)
            strData = strData + 'F';
        byte[] ret = new byte[strData.length() / 2];
        for (i = 0; i < strData.length(); i += 2) {
            if (strData.charAt(i) >= 'A' && strData.charAt(i) <= 'F')
                nData = (byte) (strData.charAt(i) - 'A' + 10);
            else
                nData = (byte) (strData.charAt(i) - '0');

            if (strData.charAt(i + 1) >= 'A' && strData.charAt(i + 1) <= 'F')
                nData2 = (byte) (strData.charAt(i + 1) - 'A' + 10);
            else
                nData2 = (byte) (strData.charAt(i + 1) - '0');
            ret[n] = (byte) (nData | (nData2 << 4));
            ++n;
        }
        return Arrays.copyOf(ret, n);
    }

    //SIM卡读ICCID
    public static String ReadICCID(DJLM_BLEService service) throws IOException //ICCID
    {
        String strRet;
        byte[] SW = new byte[2];
        /////////////////////////////////////////
        int nRet = SelectFile(service, 0x3F00, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return null;
        }
        nRet = SelectFile(service, 0x2FE2, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return null;
        }
        byte[] ret = ReadBinary(service, 0, 10, SW);
        if (ret == null || SW[0] != (byte) 0x90 || SW[1] != 0x00) {
            return null;
        }
        ///////////////////////////////////////
        if (nRet == 0 && ret != null && SW[0] == (byte) 0x90 && SW[1] == 0x00) {
            strRet = GetRevBCDString(ret);
            return strRet;
        }
        return null;
    }

    //SIM卡写IMSI和MSISDN
    /*
    static int WriteIMSIAndMSISDN_BLE(DJLM_BLEService service, String strIMSI, String strSerialNumber) throws IOException
    {
        byte[] szIMSI = GetDataFromRevBCDString("809"+strIMSI );
        strSerialNumber = "801986" + strSerialNumber + "F";
        byte[] partMSISDN = GetDataFromRevBCDString(strSerialNumber);
        byte[] szBLECmd = new byte[14];
        System.arraycopy(szIMSI, 1,szBLECmd, 0, 8);
        System.arraycopy(partMSISDN, 3,szBLECmd, 8, 6);
        byte[] ret = BLECmd(service, 3, szBLECmd, szBLECmd.length);
        if (ret == null)
            return 0;
        return -1;
    }
    */

    public static int WriteSMSP(DJLM_BLEService service, String strNum, boolean bGotoPath) throws IOException {
        int nRet;
        byte[] SW = new byte[2];
        //////////////////////////////////////////////////////////
        //Write SMSP
        byte[] szSMSP = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFD, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x08, (byte) 0x91, (byte) 0x68, (byte) 0x31, (byte) 0x10, (byte) 0x90, (byte) 0x96, (byte) 0x05, (byte) 0xF0, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};

        if (strNum != null) {
            strNum = "801986" + strNum + "F";
            byte[] partSMSP = GetDataFromRevBCDString(strNum);
            System.arraycopy(partSMSP, 0, szSMSP, 25, partSMSP.length);
        }

        if (bGotoPath) {
            nRet = SelectFile(service, 0x3F00, SW);
            if (nRet != 0 || SW[0] != (byte) 0x9F) {
                return -1;
            }
            nRet = SelectFile(service, 0x7F10, SW);
            if (nRet != 0 || SW[0] != (byte) 0x9F) {
                return -1;
            }
        }
        nRet = SelectFile(service, 0x6F42, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return -1;
        }

        nRet = WriteRecord(service, 1, 4, szSMSP, SW);
        if (nRet != 0 || SW[0] != (byte) 0x90 || SW[1] != (byte) 0x00) {
            return -1;
        }
        return 0;
    }

    static int WriteMSISDN(DJLM_BLEService service, String strSerialNumber, boolean bGotoPath) throws IOException {
        int nRet;
        byte[] SW = new byte[2];
        ///////////////////////////////////////////////////////////
        //Write MSISDN
        byte[] szMSISDN = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x08, (byte) 0x91, (byte) 0x68, (byte) 0x81, (byte) 0x16, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0xF0, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
        strSerialNumber = "801986" + strSerialNumber + "F";
        byte[] partMSISDN = GetDataFromRevBCDString(strSerialNumber);
        System.arraycopy(partMSISDN, 0, szMSISDN, 14, partMSISDN.length);
        if (bGotoPath) {
            nRet = SelectFile(service, 0x3F00, SW);
            if (nRet != 0 || SW[0] != (byte) 0x9F) {
                return -1;
            }
            nRet = SelectFile(service, 0x7F10, SW);
            if (nRet != 0 || SW[0] != (byte) 0x9F) {
                return -1;
            }
        }
        nRet = SelectFile(service, 0x6F40, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return -1;
        }

        nRet = WriteRecord(service, 1, 4, szMSISDN, SW);
        if (nRet != 0 || SW[0] != (byte) 0x90 || SW[1] != (byte) 0x00) {
            return -1;
        }
        return 0;
    }

    static int WriteIMSI(DJLM_BLEService service, String strIMSI) throws IOException {
        int nRet;
        byte[] SW = new byte[2];
        ///////////////////////////////////////////////////////////////////////
        //Write IMSI
        byte[] szIMSI = GetDataFromRevBCDString("809" + strIMSI);
        nRet = WriteIMSI(service, szIMSI, SW);
        if (nRet != 0) {
            return -1;
        } else if (nRet == 0 && (SW[0] != (byte) 0x90 || SW[1] != 0x00)) {
            return ((SW[0] << 8) | SW[1]);
        }
        return 0;
    }

    //SIM卡写IMSI和MSISDN
    public static int WriteIMSIAndMSISDN(DJLM_BLEService service, String strIMSI, String strSerialNumber) throws IOException {
        int nRet;
        byte[] SW = new byte[2];
        //////////////////////////////////////////////////////////
        //Write SMSP
        String strNum = "13010969500";
        strNum = strSerialNumber;
        nRet = WriteSMSP(service, strNum, true);
        if (nRet != 0)
            return nRet;
        if (false) {
            ///////////////////////////////////////////////////////////
            nRet = WriteMSISDN(service, strSerialNumber, true);
            if (nRet != 0)
                return nRet;
        }
        ///////////////////////////////////////////////////////////////////////
        //Write IMSI
        nRet = WriteIMSI(service, strIMSI);
        if (nRet != 0)
            return nRet;
        return 0;
    }

    //SIM卡读IMSI
    static String ReadIMSI(DJLM_BLEService service) throws IOException //IMSI
    {
        String strRet;
        byte[] SW = new byte[2];
        /////////////////////////////////////////
        int nRet = SelectFile(service, 0x3F00, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return null;
        }
        nRet = SelectFile(service, 0x7F20, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return null;
        }
        nRet = SelectFile(service, 0x6F07, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return null;
        }
        byte[] ret = ReadBinary(service, 0, 9, SW);
        if (ret == null || SW[0] != (byte) 0x90 || SW[1] != 0x00) {
            return null;
        }
        ///////////////////////////////////////
        if (nRet == 0 && ret != null && SW[0] == (byte) 0x90 && SW[1] == 0x00) {
            strRet = GetRevBCDString(ret);
            return strRet.substring(3);
        }
        return null;
    }

    static String ReadIMSI_2(DJLM_BLEService service) throws IOException //IMSI
    {
        String strRet;
        byte[] SW = new byte[2];
        /////////////////////////////////////////
        int nRet = SelectFile(service, 0x3F00, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return null;
        }
        nRet = SelectFile(service, 0x7FF0, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return null;
        }

        byte[] ret = GetResponse(service, 16, SW);
        if (ret == null || SW[0] != (byte) 0x90 || SW[1] != 0x00) {
            return null;
        }

        nRet = SelectFile(service, 0x6F07, SW);
        if (nRet != 0 || SW[0] != (byte) 0x9F) {
            return null;
        }
        ret = ReadBinary(service, 0, 9, SW);
        if (ret == null || SW[0] != (byte) 0x90 || SW[1] != 0x00) {
            return null;
        }
        ///////////////////////////////////////
        if (nRet == 0 && ret != null && SW[0] == (byte) 0x90 && SW[1] == 0x00) {
            strRet = GetRevBCDString(ret);
            return strRet.substring(3);
        }
        return null;
    }
}
